<?php

    /**
    * Mukei Development Framework
    *
    * Mukei is a development framework system created to provide developers
    * two main features: a plugin architecture which and expand the
    * functionality of the system and an event system which allows exansion of
    * existing plugins without modifing the original code.  The Mukei
    * development framework system can speed up development of new web
    * applications and reduce maintenance time of existing code.
    *
    * This file is part of Mukei.
    *
    * Mukei is free software; you can redistribute it and/or modify it under
    * the terms of the GNU General Public License as published by the Free
    * Software Foundation; either version 3 of the License, or (at your option)
    * any later version.
    *
    * Mukei is distributed in the hope that it will be useful, but WITHOUT ANY
    * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    * FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
    * details.
    *
    * You should have received a copy of the GNU General Public License
    * along with this program.  If not, see <http://www.gnu.org/licenses/>.
    *
    * @package   Mukei
    * @version   0.2
    * @author    Kevin Herrera
    * @license   http://www.gnu.org/licenses/gpl.txt GNU GPL v3
    * @copyright Copyright (c) 2007 Kevin Herrera.
    */

    /**
    * Smarty System Plugin
    *
    * This system plugin acts as a bridge between the Smarty template engine
    * by the PHP Group.  This plugin provides all of the hooks and call-
    * forwarding for the Smarty template engine so that no modifications to
    * the Smarty code is needed.  This system plugin also performs various
    * checks on directories and files to make sure that the Smarty template
    * engine was properly installed.  All variable requests and method calls
    * to the Smarty template engine must be made through the TPL handle:
    * $M->TPL->assign(), $M->TPL->template_dir, etc...
    *
    * @package Template
    * @version 0.2
    * @final
    */
    final class Template
    {
        /**#@+
        * @access public
        * @var    const
        */
        const AUTHOR   = "Kevin Herrera";
        const DESC     = "Smarty template engine bridge.";
        const HANDLE   = "TPL";
        const NAME     = "Mukei Smarty Bridge";
        const REQUIRED = "0.2";
        const VERSION  = "0.2";
        /**#@-*/

        /**
        * @access private
        * @var    array
        */
        private $_config = array( );

        /**
        * @access private
        * @var    object
        */
        private $_handle;

        /**
        * Class Constructor
        *
        * This system method will load the system settings, check various
        * directories that are required for the Smarty template to function
        * properly, check to see if Smarty was properly installed, load the
        * Smarty template engine, and automatically configure Smarty with path
        * information.  If the settings cannot be loaded or a directory is
        * missing, a fatal error will be triggered.  If there is no default
        * template configured or the default does not exist, the system default
        * template called "default" will be used.  If the default template
        * directory does not exist, a fatal error will be triggered.  Once the
        * checking is completed, the Smarty class will be loaded, initialized,
        * and configured for use.
        *
        * @access public
        * @uses   m_data()
        * @uses   m_path()
        * @return object
        */
        public function __construct ( )
        {
            // Load settings.
            if ( ( $this->_config = m_data( "Template" ) ) === null )
            {
                // Report fatal error.
                trigger_error( "Unable to load settings.",
                               E_USER_ERROR );
            }

            // Templates directory missing?
            if ( !defined( 'M_TEMPLATES_DIR' ) )
            {
                // Report fatal error.
                trigger_error( "The \"templates\" directory does not exist.",
                               E_USER_ERROR );
            }

            // Templates directory has errors?
            if ( !m_path( M_TEMPLATES_DIR,
                          M_DIRECTORY,
                          true ) )
            {
                // Report fatal error.
                trigger_error( "Templates directory has errors.",
                               E_USER_ERROR );
            }

            // Create paths.
            $smarty_path   = M_LIBRARY_DIR . "Smarty" . M_SEP;
            $class_path    = $smarty_path  . "Smarty.class.php";
            $compile_path  = M_TEMP_DIR    . "Smarty";
            $template_path = M_TEMPLATES_DIR;

            // Smarty directory has errors?
            if ( !m_path( $smarty_path, M_DIRECTORY, true ) )
            {
                // Report fatal error.
                trigger_error( "Smarty library directory has errors.",
                               E_USER_ERROR );
            }

            // Smarty class file has errors?
            if ( !m_path( $class_path, M_FILE, true ) )
            {
                // Report fatal error.
                trigger_error( "Smarty class file has errors.",
                               E_USER_ERROR );
            }

            // Compile directory has errors?
            if ( !m_path( $compile_path, M_DIRECTORY, true, true ) )
            {
                // Report fatal error.
                trigger_error( "Smarty compile directory has errors.",
                               E_USER_ERROR );
            }

            // No template configured?
            if ( empty( $this->_config['template'] ) )
            {
                // Set default.
                $this->_config['template'] = "default";
            }

            // Update path.
            $template_path .= $this->_config['template'] . M_SEP;

            // Template directory has errors?
            if ( !@m_path( $template_path, M_DIRECTORY, true ) )
            {
                // Set default.
                $this->_config['template'] = "default";
            }

            // Update path.
            $template_path = M_TEMPLATES_DIR            .
                             $this->_config['template'] .
                             M_SEP;

            // Template directory still has errors?
            if ( !m_path( $template_path, M_DIRECTORY, true ) )
            {
                // Report fatal error.
                trigger_error( "Template, " . $this->_config['template'] .
                               ", has errors.",
                               E_USER_ERROR );
            }

            // Load Smarty.
            require( $class_path );

            // Missing Smarty class?
            if ( !class_exists( "Smarty" ) )
            {
                // Report fatal error.
                trigger_error( "Smarty class could not be found.",
                               E_USER_ERROR );
            }

            // Initialize.
            $this->_handle = new Smarty ( );

            // Configure Smarty.
            $this->compile_dir  = $compile_path;
            $this->template_dir = $template_path;

            // Assign Smarty vars.
            $this->assign( "mukei_version", Mukei::VERSION  );
            $this->assign( "base_url", M_BASE_URL );
            $this->assign( "template_url",
                           M_TEMPLATES_URL            .
                           $this->_config['template'] . "/" );
        }

        /**
        * Call Method
        *
        * This system method simply redirects all calls to methods that do
        * not exist in this class to Smarty.  If the method does not exist,
        * a fatal error will be triggered stating the problem.  This method,
        * however, does not take into account the visibility of the method in
        * the Smarty class.  If a private method (if any exists) is called,
        * PHP will trigger a fatal error.
        *
        * @access public
        * @param  string $method Method name.
        * @param  array  $args   Method arguments.
        * @return mixed
        */
        public function __call ( $method,
                                 $args )
        {
            // Smarty method exists?
            if ( method_exists( $this->_handle,
                                $method ) )
            {
                // Call method.
                return( call_user_func_array( array( $this->_handle,
                                                     $method ),
                                              $args ) );
            }

            // Smarty method does not exist?
            else
            {
                // Report fatal error.
                trigger_error( "Smarty method, $method, does not exist.",
                               E_USER_ERROR );
            }
        }

        /**
        * Get Property
        *
        * This system method return the value of the property of the Smarty
        * class if the property exists.  If the property does not exist, a
        * notice will be triggered and no value will be returned.  To determine
        * if a property exists, isset() should be used on the property
        * requested.
        *
        * @access public
        * @see    isset()
        * @param  string $property Property name.
        * @return mixed
        */
        public function __get ( $property )
        {
            // Have Smarty property?
            if ( isset( $this->_handle->$property ) )
            {
                // Return it.
                return( $this->_handle->$property );
            }

            // No Smarty property?
            else
            {
                // Report notice.
                trigger_error( "Smarty property, $property, does not exist.",
                               E_USER_NOTICE );
            }
        }

        /**
        * Is Property Set?
        *
        * This system method will check to see if the property exists in the
        * Smarty class.  If the property exists (regardless of the value), the
        * boolean value of true will be returned.  If the property does not
        * exist or is set to null (see PHP's isset() function documentation),
        * the boolean value of false will be returned.
        *
        * @access public
        * @param  string  $property Property name.
        * @return boolean
        */
        public function __isset ( $property )
        {
            // Is property set?
            if ( isset( $this->_handle->$property ) )
            {
                // Yes.
                return( true );
            }

            return( false );
        }

        /**
        * Set Property
        *
        * This system method will set the property with the given value.  The
        * only possible error that could be triggered, would be triggered by
        * PHP.  That error would be about the visibility of the property.  If
        * the property is private or protected, PHP will raise a fatal error.
        *
        * @access public
        * @param  string $property Property name.
        * @param  mixed  $value    Property value.
        * @return void
        */
        public function __set ( $property,
                                $value )
        {
            // Set Smarty property.
            $this->_handle->$property = $value;
        }
    }

?>